﻿using Basic.FlowApplication.AuditLocalEvent;
using Basic.FlowApplication.Interface;
using Basic.FlowApplication.Model;
using Basic.FlowModel.AuditLog;
using Basic.FlowModel.AuditLogItem;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Application.Model;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.Extend
{
    internal class AuditService : IAuditService
    {
        private readonly IFlowAppService _FlowApp;
        private readonly IAuditLogService _AuditLog;
        private readonly IFlowNodeService _Flow;
        private readonly IFlowNextStepService _NextStep;
        public AuditService ( IFlowAppService flowApp,
            IAuditLogService auditLog,
            IFlowNodeService flow,
            IFlowNextStepService nextStep )
        {
            this._FlowApp = flowApp;
            this._AuditLog = auditLog;
            this._Flow = flow;
            this._NextStep = nextStep;
        }

        public NextStepResult GetNextStep ( long itemId )
        {
            AuditItemLog log = this._AuditLog.GetItem(itemId);
            if ( log.Status != FlowAuditItemStatus.审核进行中 )
            {
                throw new ErrorException("flow.audit.status.change");
            }
            AuditFlowBody flow = this._Flow.Get(log.FlowId);
            return this._NextStep.GetNextNode(flow, log);
        }
        private AuditFlowBody _GetFlow ( FlowAppBody app, string ver )
        {
            if ( ver.IsNull() || ver == app.FlowVer )
            {
                return this._Flow.Get(app.FlowId.Value);
            }
            return this._Flow.Get(app.FlowId.Value, ver);
        }
        public CreateAuditResult BeginAudit ( BeginFlowArg arg, FlowUser user )
        {
            if ( this._AuditLog.IsInProgress(arg.AppId, arg.LinkType, arg.LinkPk) )
            {
                throw new ErrorException("flow.audit.already.begin");
            }
            FlowAppBody app = this._FlowApp.Get(arg.AppId);
            if ( app.AppType == FlowAppType.内部应用 )
            {
                throw new ErrorException("flow.app.type.error");
            }
            else if ( app.Status != FlowAppStatus.启用 )
            {
                throw new ErrorException("flow.app.status.error");
            }
            AuditFlowBody flow = this._GetFlow(app, arg.Ver);
            if ( flow.Status != FlowStatus.启用 )
            {
                throw new ErrorException("flow.node.status.error");
            }
            FlowNode node = flow.Nodes[flow.BeginNode];
            AuditLogAdd add = new AuditLogAdd
            {
                DocTitle = arg.DocTitle,
                CreateByDeptId = user.DeptId,
                CompanyId = user.CompanyId,
                BeginNodeId = flow.BeginNode,
                AppId = app.Id,
                AppType = app.AppType,
                CreateBy = user.EmpId,
                CreateByUnitId = user.UnitId,
                FlowId = app.FlowId.Value,
                FormId = node.FormId.GetValueOrDefault(flow.DefFormId.Value),
                LinkPk = arg.LinkPk,
                LinkType = arg.LinkType,
                NodeId = flow.Nodes.Select(a => new KeyValuePair<long, long>(a.Key, a.Value.RootNodeId)).ToArray(),
            };
            CreateResult res = this._AuditLog.Create(add);
            new AuditBeginEvent
            {
                Body = new AuditBeginBody
                {
                    DocTitle = arg.DocTitle,
                    Flow = flow,
                    App = app,
                    LinkPk = arg.LinkPk,
                    LinkType = arg.LinkType,
                    LogId = res.LogId,
                    ItemId = res.ItemId,
                    ToVoidLogId = res.ToVoidId,
                    ToVoidItemId = res.ToVoidItemId,
                    User = user
                }
            }.AsyncSend();
            return new CreateAuditResult
            {
                ItemId = res.ItemId,
                LogId = res.LogId,
                IsNext = node.IsSign == false && node.IsUpFile == false && node.IsUpFileSign == false
            };
        }
    }
}
